home *** CD-ROM | disk | FTP | other *** search
/ NeXT Education Software Sampler 1992 Fall / NeXT Education Software Sampler 1992 Fall.iso / Programming / Source / Guitar / fracdelay.asm < prev    next >
Encoding:
Assembly Source File  |  1992-07-28  |  8.6 KB  |  216 lines

  1. ;;  fracdelay.asm
  2. ;;  Author - Rick Vander Kam
  3. ;;  Copyright (c)1992 - All rights reserved
  4. ;;  Modification history
  5. ;;  --------------------
  6. ;;  02/01/92/rvk - initial file created from /usr/lib/dsp/ugsrc/delay.asm
  7. ;;            no length-changing procedures, two FIR bins
  8. ;;  02/02/92/rvk - added length-changing procedures, reduced to one FIR bin,
  9. ;;            added updates of bb0 and bb1 coeffs and end address arg
  10. ;;            
  11. ;;
  12. ;;------------------------------ DOCUMENTATION ---------------------------
  13. ;;  NAME
  14. ;;      fracdelay (UG macro) - sample-based interpolated delay line using non-modulo indexing
  15. ;;
  16. ;;  SYNOPSIS
  17. ;;      fracdelay pf,ic,sout,aout0,sinp,ainp0,sdel,adel0,pdel0,edel0,afir0,bb00,bb10,chg0
  18. ;;
  19. ;;  MACRO ARGUMENTS
  20. ;;      pf        = global label prefix (any text unique to invoking macro)
  21. ;;      ic        = instance count (s.t. pf\_fracdelay_\ic\_ is globally unique)
  22. ;;      sout      = output vector memory space ('x' or 'y')
  23. ;;      aout0     = initial output vector memory address
  24. ;;      sinp      = input vector memory space ('x' or 'y')
  25. ;;      ainp0     = initial input vector memory address
  26. ;;      sdel      = delay-line memory space ('x' or 'y')
  27. ;;      adel0     = delay-line start address
  28. ;;      pdel0     = delay-line pointer
  29. ;;      edel0     = address of first sample beyond delay line
  30. ;;      afir0        = address of undelayed sample in FIR filter
  31. ;;    bb00        = coefficient of undelayed sample in FIR filter
  32. ;;    bb10        = coefficient of once-delayed sample
  33. ;;    chg0    = datum arg flag for changing length of delay line
  34. ;;
  35. ;;  DSP MEMORY ARGUMENTS
  36. ;;      Access         Description              Initialization
  37. ;;      ------                   -----------              --------------
  38. ;;      x:(R_X)+       Output address           aout0
  39. ;;      x:(R_X)+       Input address            ainp0
  40. ;;    x:(R_X)+        FIR filter address       afir0
  41. ;;      x:(R_X)+        bb0 coefficient              bb00
  42. ;;      x:(R_X)+       Delay pointer            pdel0
  43. ;;      y:(R_Y)+       Start address            adel0  
  44. ;;    y:(R_Y)+      change flag                chg0 
  45. ;;      y:(R_Y)+       Last address + 1         edel0
  46. ;;      y:(R_Y)+       bb1 coefficient             bb10
  47. ;;
  48. ;;  DESCRIPTION
  49. ;;
  50. ;;      The fracdelay unit-generator implements an interpolated delay line which
  51. ;;    can produce fractional-sample delays.  It uses a circular
  52. ;;      buffer (not modulo storage) followed by a two-point FIR filter.  Therefore, this
  53. ;;      UG does not result in a pure delay, but also affects the spectral characteristics
  54. ;;    of the signal (the FIR filter is low-pass).  It is well-suited for use in the
  55. ;;    Karplus/Strong plucked-string model.
  56. ;;
  57. ;;      For best performance, the input and output signals should be in the same
  58. ;;      memory space, which should be different from the delay-line memory space.
  59. ;;      I.e., if the delay table is in x memory, both input and output should be 
  60. ;;      in y memory, or vice versa.
  61. ;;      
  62. ;;      In pseudo-C notation:
  63. ;;
  64. ;;      aout = x:(R_X)+;
  65. ;;      ainp = x:(R_X)+;
  66. ;;    afir    = x:(R_X)+;
  67. ;;    bb0= x:(R_X)+;
  68. ;;      pdel = x:(R_X)+;
  69. ;;      adel = y:(R_Y)+;
  70. ;;    chg = y:(R_Y)+;
  71. ;;      edel = y:(R_Y)+;
  72. ;;    bb1 = y:(R_Y)+;
  73. ;;
  74. ;;      for (n=0;n<I_NTICK;n++) {
  75. ;;           sout:aout[n] = sdel:(afir)*bb0+(afir+1)*bb1;
  76. ;;        sdel:(afir+1) = sdel:(afir);
  77. ;;        sdel:(afir)=sdel:(pdel)
  78. ;;           sdel:(pdel) = sinp:ainp[n];
  79. ;;           if (++pdel>=edel) pdel=adel;   plus other stuff to handle lengthening/shortening
  80. ;;      }
  81. ;;
  82. ;;  DSPWRAP ARGUMENT INFO
  83. ;;      fracdelay (prefix)pf,(instance)ic, (dspace)sout,(output)aout, (dspace)sinp,(input)ainp,
  84. ;;         (dspace)sdel,(address)adel,(address)pdel,(address)edel,(address)afir,
  85. ;;        bb0,bb1,chg
  86. ;;        
  87. ;;         
  88. ;;
  89. ;;  MAXIMUM EXECUTION TIME
  90. ;;      ??? DSP clock cycles for one "tick" which equals 16 audio samples.
  91. ;;
  92. ;;  MINIMUM EXECUTION TIME
  93. ;;      ??? DSP clock cycles for one "tick".
  94. ;;
  95. ;;  SOURCE
  96. ;;      /user/rvk/ee265/test/fracdelay.asm
  97. ;;
  98. ;;  ALU REGISTER USE
  99. ;;      X0 = b0 coefficient
  100. ;;      X1 = b1 coefficient
  101. ;;      Y1 = start address of delay line
  102. ;;      Y0 = last address of delay line
  103. ;;       A = temporary register for input signal
  104. ;;       B = temporary register for output signal
  105. ;;
  106. fracdelay     macro pf,ic,sout,aout0,sinp,ainp0,sdel,adel0,pdel0,edel0,afir0,bb00,bb10,chg0
  107.                new_xarg pf\_fracdelay_\ic\_,aout,aout0   ; output address arg
  108.                new_xarg pf\_fracdelay_\ic\_,ainp,ainp0   ; input address arg
  109.           new_xarg pf\_fracdelay_\ic\_,afir,afir0   ; filter address arg
  110.            new_xarg pf\_fracdelay_\ic\_,bb0,bb00   ;
  111.                new_xarg pf\_fracdelay_\ic\_,pdel,pdel0   ; current pointer arg
  112.                new_yarg pf\_fracdelay_\ic\_,adel,adel0   ; start-address arg
  113.            new_yarg pf\_fracdelay_\ic\_,chg,chg0   ;
  114.                new_yarg pf\_fracdelay_\ic\_,edel,edel0   ; last-address+1 arg
  115.            new_yarg pf\_fracdelay_\ic\_,bb1,bb10   ;
  116.  
  117.           move R_L,N_O        ;safe keeping
  118.                move x:(R_X)+,R_O         ; output address to R_O
  119.                move x:(R_X)+,R_I1       ; input address to R_I1
  120.            move x:(R_X)+,R_L        ;FIR address to R_L
  121.            move x:(R_X)+,X0 y:(R_Y)+,Y1        ; bb0 to X0 (update), delay line start adr to Y1
  122.            move y:(R_Y)+,N_I1    ;flag for changing delay line length
  123.         move y:(R_Y)+,Y0 ; ad of end+1  to Y0 (update on exit)
  124.            move y:(R_Y),X1        ;bb1 to X1 (update on exit)
  125.                move x:(R_X),R_I2        ; delay ptr to R_I2  (update on exit)
  126.  
  127.                move R_I2,A              ; current delay pointer expected in A
  128.                do #I_NTICK,pf\_fracdelay_\ic\_tickloop
  129.                     cmp Y0,A            ; check against last address + 1
  130.                     tge Y1,A            ; wrap around if necessary
  131.  
  132.         jlt pf\_fracdelay_\ic\_notend
  133.         clr B Y0,N_I2        ; 0 in B, save Y0
  134.         move N_I1,Y0    ;chg flag to Y0
  135.         cmp Y0,B        ; check flag against 0
  136.         btst #$F,Y0        ; check for pos or neg 16-bit number
  137.         move N_I2,Y0    ;restore value
  138.         jeq pf\_fracdelay_\ic\_notend    ;no change if 0
  139.         jcs pf\_fracdelay_\ic\_shrink        ;flag <0 => check for shrinking
  140.         
  141.         ; Here to check for growing
  142.         cmp X0,B    ;check bb0 coeff
  143.         jne pf\_fracdelay_\ic\_notend    ;nonzero coeff => no change in length
  144.         ;here only if growing
  145.         move sinp:(R_I1)+,A      ;new input to A
  146.         move A,sdel:(R_I2)+     ;write new last cell
  147.         move B,X1        ; clear bb1
  148.         move R_I2,Y0        ; increase end addr by 1
  149.         move sdel:(R_L),B            ;new output sample to B
  150.         move Y1,R_I2            ; addr of cell 1 in R_I2
  151.         move B,sout:(R_O)+        ; ship output sample
  152.         move #$7FFFFF,X0        ;set bb0 to 1
  153.         move X0,x:-(R_X)     ;update bb0 
  154.                  move Y0,y:-(R_Y)    ;update delay line end addr
  155.         move x:(R_X)+,X0 y:(R_Y)+,Y0    ;dummy reads
  156.         jmp pf\_fracdelay_\ic\_niter  ;go to next iteration
  157.         
  158. pf\_fracdelay_\ic\_shrink
  159.         ;Here to check for shrinking
  160.         cmp X1,B
  161.         jne pf\_fracdelay_\ic\_notend  ;no change if bb1 != 0
  162.         ;here only if shrinking
  163.         move R_X,N_X    ;save
  164.         move Y1,R_X        ;cell 1 addr to R_X
  165.         move sdel:-(R_I2),A     ;recover last input
  166.         move B,X0            ; clr bb0
  167.         move sdel:(R_X),B        ;new output to B
  168.         if "sdel"!="sout"        ;ship output, last input to cell 1
  169.             move B,sout:(R_O)+ A,sdel:(R_X)+
  170.         else
  171.             move A,sdel:(R_X)+
  172.             move B,sout:(R_O)+
  173.         endif
  174.         move #$7FFFFF,X1    ;set bb1 to 1
  175.         move sdel:(R_X),A      ;cell 2 to A
  176.         move R_I2,Y0        ; new end addr to Y0
  177.         move sinp:(R_I1)+,B    ;new input to B
  178.         move B,sdel:(R_X)+    ;new input to cell 2
  179.         move A,sdel:(R_L)        ;old cell 2 to undel bin
  180.         move R_X,R_I2            ;cell 3 addr to R_I2 (to A below)
  181.         move N_X,R_X        ;restore
  182.                  move Y0,y:-(R_Y)    ;update delay line end addr
  183.         move X0,x:-(R_X)     ;update bb0 
  184.         move x:(R_X)+,X0 y:(R_Y)+,Y0    ;dummy reads
  185.         jmp pf\_fracdelay_\ic\_niter    ;go to next iteration
  186.  
  187. pf\_fracdelay_\ic\_notend  
  188.                     move A,R_I2         ; delay pointer for next entry
  189.         move Y0,N_I2        ;clear out Y0
  190.  
  191.                     ; load current input to A, current delay value to B
  192.          if "sinp"=="sdel"
  193.                          move sinp:(R_I1)+,A      ; 
  194.                          move sdel:(R_I2),B  ;  no post-increment!
  195.          else
  196.                            move  sdel:(R_I2),B sinp:(R_I1)+,A
  197.                     endif
  198.  
  199.                     ; output current delay-line value, overwrite with input (general case)
  200.         move sdel:(R_L),Y0     ;prev undelayed samp to Y0
  201.         move A,sdel:(R_I2)+     ;new sample is written
  202.         mpy X1,Y0,A              ;b1*(once-delayed)
  203.         move B,Y0            ; current  del line value to Y0 as undelayed
  204.         mac X0,Y0,A Y0,sdel:(R_L)    ;output sample is in A, new undel to its bin
  205.         move A,sout:(R_O)+            ;ship the output
  206.         move N_I2,Y0                ;restore end address value
  207. pf\_fracdelay_\ic\_niter
  208.         move R_I2,A         ; delay pointer for next entry
  209. pf\_fracdelay_\ic\_tickloop    
  210.         move N_O,R_L       ; restore R_L
  211.                   move A,x:(R_X)+           ; save delay pointer for next entry
  212.         move X1,y:(R_Y)+        ;update bb1
  213.      endm
  214.  
  215.  
  216.